//----------------------------------------------------------------------------
//  ,-.
// /_\___ ,   Ninja Framework
// '  ___\    (C) Riccardo Capra - http://riccar.do
//  //   \\
//----------------------------------------------------------------------------
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------

#ifndef NJ_ATOMIC_BASE_WIN_INLINE_H
#	define NJ_ATOMIC_BASE_WIN_INLINE_H

	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::NjAtomicBase()
	{
#	if NJ_ASSERT_ENABLED
		TestAlignment();
#	endif // NJ_ASSERT_ENABLED
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::NjAtomicBase(NjAtomicBase const & kCopy)
	:
		m_iNumber(kCopy.m_iNumber)
	{
#	if NJ_ASSERT_ENABLED
		TestAlignment();
#	endif // NJ_ASSERT_ENABLED
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::NjAtomicBase(Number iCopy)
	:
		m_iNumber(iCopy)
	{
#	if NJ_ASSERT_ENABLED
		TestAlignment();
#	endif // NJ_ASSERT_ENABLED
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::~NjAtomicBase()
	{
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<4>::Increment()
	{
		PreIncrement();
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PreIncrement()
	{
		return static_cast<Number>(_InterlockedIncrement(reinterpret_cast<long volatile *>(&m_iNumber)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostIncrement()
	{
		return PreIncrement()-1;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<4>::Decrement()
	{
		PreDecrement();
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PreDecrement()
	{
		return static_cast<Number>(_InterlockedDecrement(reinterpret_cast<long volatile *>(&m_iNumber)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostDecrement()
	{
		return PreDecrement()+1;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<4>::Add(Number iRightValue)
	{
		PostAdd(iRightValue);
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PreAdd(Number iRightValue)
	{
		return PostAdd(iRightValue)+iRightValue;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostAdd(Number iRightValue)
	{
		return static_cast<Number>(_InterlockedExchangeAdd(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long>(iRightValue)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<4>::Sub(Number iRightValue)
	{
		Add(-iRightValue);
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PreSub(Number iRightValue)
	{
		return PreAdd(-iRightValue);
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostSub(Number iRightValue)
	{
		return PostAdd(-iRightValue);
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostOr(Number iRightValue)
	{
		return static_cast<Number>(_InterlockedOr(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long>(iRightValue)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostAnd(Number iRightValue)
	{
		return static_cast<Number>(_InterlockedAnd(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long>(iRightValue)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostXor(Number iRightValue)
	{
		return static_cast<Number>(_InterlockedXor(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long>(iRightValue)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostExchange(Number iValue)
	{
		return static_cast<Number>(_InterlockedExchange(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long>(iValue)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::PostCompareExchange(Number iComparand, Number iValue)
	{
		return static_cast<Number>(_InterlockedCompareExchange(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long>(iValue), static_cast<long>(iComparand)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjBool NjAtomicBase<4>::PostSetBit(Number iBit)
	{
		return _interlockedbittestandset(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long>(iBit))!=FALSE;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjBool NjAtomicBase<4>::PostResetBit(Number iBit)
	{
		return _interlockedbittestandreset(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long>(iBit))!=FALSE;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<4>::Number NjAtomicBase<4>::Get() const
	{
		return m_iNumber;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<4>::Set(Number iValue)
	{
		m_iNumber=iValue;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::NjAtomicBase()
	{
#	if NJ_ASSERT_ENABLED
		TestAlignment();
#	endif // NJ_ASSERT_ENABLED
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::NjAtomicBase(NjAtomicBase const & kCopy)
	:
		m_iNumber(kCopy.m_iNumber)
	{
#	if NJ_ASSERT_ENABLED
		TestAlignment();
#	endif // NJ_ASSERT_ENABLED
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::NjAtomicBase(Number iCopy)
	:
		m_iNumber(iCopy)
	{
#	if NJ_ASSERT_ENABLED
		TestAlignment();
#	endif // NJ_ASSERT_ENABLED
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::~NjAtomicBase()
	{
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<8>::Increment()
	{
		PreIncrement();
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PreIncrement()
	{
#	if NJ_PLATFORM_64_BIT
		return static_cast<Number>(_InterlockedIncrement64(reinterpret_cast<__int64 volatile *>(&m_iNumber)));
#	else // NJ_PLATFORM_64_BIT
		return static_cast<Number>(InterlockedIncrement64(reinterpret_cast<LONGLONG volatile *>(&m_iNumber)));
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostIncrement()
	{
		return PreIncrement()-1;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<8>::Decrement()
	{
		PreDecrement();
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PreDecrement()
	{
#	if NJ_PLATFORM_64_BIT
		return static_cast<Number>(_InterlockedDecrement64(reinterpret_cast<__int64 volatile *>(&m_iNumber)));
#	else // NJ_PLATFORM_64_BIT
		return static_cast<Number>(InterlockedDecrement64(reinterpret_cast<LONGLONG volatile *>(&m_iNumber)));
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostDecrement()
	{
		return PreDecrement()+1;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<8>::Add(Number iRightValue)
	{
		PostAdd(iRightValue);
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PreAdd(Number iRightValue)
	{
		return PostAdd(iRightValue)+iRightValue;
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostAdd(Number iRightValue)
	{
#	if NJ_PLATFORM_64_BIT
		return static_cast<Number>(_InterlockedExchangeAdd64(reinterpret_cast<__int64 volatile *>(&m_iNumber), static_cast<__int64>(iRightValue)));
#	else // NJ_PLATFORM_64_BIT
		return static_cast<Number>(InterlockedExchangeAdd64(reinterpret_cast<LONGLONG volatile *>(&m_iNumber), static_cast<LONGLONG>(iRightValue)));
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<8>::Sub(Number iRightValue)
	{
		Add(-iRightValue);
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PreSub(Number iRightValue)
	{
		return PreAdd(-iRightValue);
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostSub(Number iRightValue)
	{
		return PostAdd(-iRightValue);
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostOr(Number iRightValue)
	{
#	if NJ_PLATFORM_64_BIT
		return static_cast<Number>(_InterlockedOr64(reinterpret_cast<__int64 volatile *>(&m_iNumber), static_cast<__int64>(iRightValue)));
#	else // NJ_PLATFORM_64_BIT
		return static_cast<Number>(InterlockedOr64(reinterpret_cast<LONGLONG volatile *>(&m_iNumber), static_cast<LONGLONG>(iRightValue)));
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostAnd(Number iRightValue)
	{
#	if NJ_PLATFORM_64_BIT
		return static_cast<Number>(_InterlockedAnd64(reinterpret_cast<__int64 volatile *>(&m_iNumber), static_cast<__int64>(iRightValue)));
#	else // NJ_PLATFORM_64_BIT
		return static_cast<Number>(InterlockedAnd64(reinterpret_cast<LONGLONG volatile *>(&m_iNumber), static_cast<LONGLONG>(iRightValue)));
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostXor(Number iRightValue)
	{
#	if NJ_PLATFORM_64_BIT
		return static_cast<Number>(_InterlockedXor64(reinterpret_cast<__int64 volatile *>(&m_iNumber), static_cast<__int64>(iRightValue)));
#	else // NJ_PLATFORM_64_BIT
		return static_cast<Number>(InterlockedXor64(reinterpret_cast<LONGLONG volatile *>(&m_iNumber), static_cast<LONGLONG>(iRightValue)));
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostExchange(Number iValue)
	{
#	if NJ_PLATFORM_64_BIT
		return static_cast<Number>(_InterlockedExchange64(reinterpret_cast<__int64 volatile *>(&m_iNumber), static_cast<__int64>(iValue)));
#	else // NJ_PLATFORM_64_BIT
		return static_cast<Number>(InterlockedExchange64(reinterpret_cast<LONGLONG volatile *>(&m_iNumber), static_cast<LONGLONG>(iValue)));
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::PostCompareExchange(Number iComparand, Number iValue)
	{
#	if NJ_PLATFORM_64_BIT
		return static_cast<Number>(_InterlockedCompareExchange64(reinterpret_cast<__int64 volatile *>(&m_iNumber), static_cast<__int64>(iValue), static_cast<__int64>(iComparand)));
#	else // NJ_PLATFORM_64_BIT
		return static_cast<Number>(InterlockedCompareExchange64(reinterpret_cast<LONGLONG volatile *>(&m_iNumber), static_cast<LONGLONG>(iValue), static_cast<LONGLONG>(iComparand)));
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjBool NjAtomicBase<8>::PostSetBit(Number iBit)
	{
#	if NJ_PLATFORM_64_BIT
		return _interlockedbittestandset64(reinterpret_cast<__int64 volatile *>(&m_iNumber), static_cast<__int64>(iBit))!=FALSE;
#	else // NJ_PLATFORM_64_BIT
		NJ_COMPILE_ASSERT(NJ_PLATFORM_LITTLE_ENDIAN);

		if (iBit>=32)
			return _interlockedbittestandset(reinterpret_cast<long volatile *>(&m_iNumber)+1, static_cast<long >(iBit)-32)!=FALSE;

		return _interlockedbittestandset(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long >(iBit))!=FALSE;
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjBool NjAtomicBase<8>::PostResetBit(Number iBit)
	{
#	if NJ_PLATFORM_64_BIT
		return _interlockedbittestandreset64(reinterpret_cast<__int64 volatile *>(&m_iNumber), static_cast<__int64>(iBit))!=FALSE;
#	else // NJ_PLATFORM_64_BIT
		NJ_COMPILE_ASSERT(NJ_PLATFORM_LITTLE_ENDIAN);

		if (iBit>=32)
			return _interlockedbittestandreset(reinterpret_cast<long volatile *>(&m_iNumber)+1, static_cast<long >(iBit)-32)!=FALSE;

		return _interlockedbittestandreset(reinterpret_cast<long volatile *>(&m_iNumber), static_cast<long >(iBit))!=FALSE;
#	endif // NJ_PLATFORM_64_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<8>::Number NjAtomicBase<8>::Get() const
	{
#	if NJ_PLATFORM_32_BIT
		return const_cast<NjAtomicBase *>(this)->PostCompareExchange(0, 0);
#	else // NJ_PLATFORM_32_BIT
		return m_iNumber;
#	endif // NJ_PLATFORM_32_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE void NjAtomicBase<8>::Set(Number iValue)
	{
#	if NJ_PLATFORM_32_BIT
		PostExchange(iValue);
#	else // NJ_PLATFORM_32_BIT
		m_iNumber=iValue;
#	endif // NJ_PLATFORM_32_BIT
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<1>::Number NjAtomicBase<1>::PostCompareExchange(Number iComparand, Number iValue)
	{
		NJ_COMPILE_ASSERT(NJ_PLATFORM_LITTLE_ENDIAN);

		return static_cast<Number>(_InterlockedCompareExchange8(reinterpret_cast<volatile NjChar8 *>(&m_iNumber), static_cast<NjChar8>(iValue), static_cast<NjChar8>(iComparand)));
	}
	//----------------------------------------------------------------------------
	NJ_FORCE_INLINE NjAtomicBase<2>::Number NjAtomicBase<2>::PostCompareExchange(Number iComparand, Number iValue)
	{
		NJ_COMPILE_ASSERT(NJ_PLATFORM_LITTLE_ENDIAN);

		return static_cast<Number>(_InterlockedCompareExchange16(reinterpret_cast<NjInt16 volatile *>(&m_iNumber), static_cast<NjInt16>(iValue), static_cast<NjInt16>(iComparand)));
	}
	//----------------------------------------------------------------------------

#endif // NJ_ATOMIC_BASE_WIN_INLINE_H

